#include "Spark/Net/EventLoop.h"
#include "Spark/Net/TcpClient.h"
#include "Spark/Net/SocketAddr.h"
#include "Spark/Utils/Logger.h"

#include <utility>

#include <stdio.h>
#include <unistd.h>

using namespace std::placeholders;

int numThreads = 0;
class EchoClient;
std::vector<std::unique_ptr<EchoClient>> clients;
int current = 0;

class EchoClient : NonCopyable
{
  public:
    EchoClient(EventLoop* loop, const SocketAddr& listenAddr, const string& id)
        : loop_(loop), client_(loop, listenAddr, "EchoClient" + id)
    {
        client_.setConnectionCallback(
            [this](const TcpConnectionPtr& conn) { onConnection(conn); });
        client_.setRecvMessageCallback(
            [this](const TcpConnectionPtr& conn, MsgBuffer* buffer, TimePoint tp){
                onMessage(conn, buffer, tp);
            });
        // client_.enableRetry();
    }

    void connect()
    {
        client_.connect();
    }
    // void stop();

  private:
    void onConnection(const TcpConnectionPtr& conn)
    {
        LOG_TRACE << conn->localAddr().toStringPort() << " -> "
                  << conn->peerAddr().toStringPort() << " is "
                  << (conn->connected() ? "UP" : "DOWN");

        if (conn->connected())
        {
            ++current;
            if (current < clients.size())
            {
                clients[current]->connect();
            }
            LOG_INFO << "*** connected " << current;
        }
        conn->send("world\n");
    }

    void onMessage(const TcpConnectionPtr& conn, MsgBuffer* buf, TimePoint time)
    {
        string msg(buf->retrieveAllAsString());
        LOG_TRACE << conn->name() << " recv " << msg.size() << " bytes at ";
        ++msgcnt_;
        if (msgcnt_ < 100)
            conn->send(msg);
        else
        {
            LOG_WARN << "Received 100 msg, Exit !";
            loop_->quit();
        }
    }

    EventLoop* loop_;
    TcpClient client_;
    int msgcnt_{0};
};

int main(int argc, char* argv[])
{
    LOG_INFO << "pid = " << getpid();
    if (argc > 1)
    {
        EventLoop loop;
        bool ipv6 = argc > 3;
        SocketAddr serverAddr(argv[1], 2000, ipv6);

        int n = 1;
        if (argc > 2)
        {
            n = atoi(argv[2]);
        }

        clients.reserve(n);
        for (int i = 0; i < n; ++i)
        {
            char buf[32];
            snprintf(buf, sizeof buf, "%d", i + 1);
            clients.emplace_back(new EchoClient(&loop, serverAddr, buf));
        }

        clients[current]->connect();
        loop.loop();
    }
    else
    {
        printf("Usage: %s host_ip [current#]\n", argv[0]);
    }
}
